#include "HistoryRecord.h"

#define ISVALID_DATALEN(n) (n <= HISTORY_RECORD_LEN ? 1 : 0)

CHistoryRecord :: CHistoryRecord()
{

  filefd = -1;
  fileheader = NULL;

}


CHistoryRecord :: ~CHistoryRecord()
{
   close(filefd);
}

HistoryFileHeader   * CHistoryRecord ::  HistoryInit(const char *filename, unsigned short maxrecord)
{ 
    if(fileheader != NULL) /*判断是否初始化过*/
       return fileheader;
    int res = -1;
    if((filefd = open(filename, O_RDWR|O_CREAT, 0777)) < 0)
    {  
        MY_ERROR_LOG("open file %s error : %d \n", filename, filefd);
        return NULL;
    }
    struct stat fileinfo = {0};
    if(stat(filename, &fileinfo) == 0) /*获取文件大小，判断是否为新文件*/
    {
       if(fileinfo.st_size >= 256) /*旧文件*/
       {
          res = lseek(filefd, 0, SEEK_SET);
          if(res < 0)
          {
             MY_ERROR_LOG("lseek error : %d\n", res);
             return NULL;
          }
          fileheader = (HistoryFileHeader *)malloc(sizeof(HistoryFileHeader));
          memset(fileheader, 0, sizeof(HistoryFileHeader));
          if(read(filefd,  (void *)fileheader, sizeof(HistoryFileHeader)) < 0)
          {
              MY_ERROR_LOG("read file header error\n");
              free(fileheader);
              fileheader = NULL;
              return NULL;
          }
          return fileheader;
       }
       else /*新文件*/
       {
           fileheader = (HistoryFileHeader *)malloc(sizeof(HistoryFileHeader));
           memset(fileheader, 0, sizeof(HistoryFileHeader));
           fileheader->header = 0x55aa55aa;
           fileheader->maxrecord = maxrecord;
           memcpy(fileheader->tag, TAG_STR, strlen(TAG_STR));
           memcpy(fileheader->version, VERSION_STR, strlen(VERSION_STR));
           if(write(filefd, (void *)fileheader, sizeof(HistoryFileHeader)) < 0)
           {
               MY_ERROR_LOG("write file header error\n");
               free(fileheader);
               fileheader = NULL;
               return NULL; 
           }
           return fileheader;
       }
    }
    return NULL;
}

int CHistoryRecord :: HistorySetValid(unsigned char valid, int writeindex)
{
    if(filefd >= 0)
    {
          int res = lseek(filefd, 256+writeindex*sizeof(HistoryRecordHeader), SEEK_SET);
          if(res >= 0)
          {
              HistoryRecordHeader temprecordheader = {0};
              int recordlen = sizeof(HistoryRecordHeader);
              if(recordlen == read(filefd, (void *)&temprecordheader, recordlen))
               {
                    temprecordheader.valid = valid;
                    lseek(filefd, 256+writeindex*sizeof(HistoryRecordHeader), SEEK_SET);
                    if(write(filefd, &temprecordheader, sizeof(HistoryRecordHeader)) > 0)
                    {
                    }
                    else
                    {
                        MY_ERROR_LOG("write error\n", res);
                        return -1;
                    }
               }
               else
               {
                 MY_ERROR_LOG("read error\n", res);
                 return -1;
               }
          }
          else
          {
            MY_ERROR_LOG("lseek error : %d\n", res);
            return -1;
          }
    }
    else
    {
         MY_ERROR_LOG("file no init\n");
         return -1;
    }     
     return 0;
}

int CHistoryRecord :: HistoryWrite(char *historydata, int datalen, int writeindex)
{
   if(0 == ISVALID_DATALEN(datalen) )
   {
       MY_ERROR_LOG("write data %d is more than max data len %d", datalen, HISTORY_RECORD_LEN);
       return - 1;
   }
   if(filefd >= 0)
    {
          int res = lseek(filefd, 256+writeindex*sizeof(HistoryRecordHeader), SEEK_SET);
          if(res >= 0)
          {
              HistoryRecordHeader temprecordheader = {0};
              int recordlen = sizeof(HistoryRecordHeader);
              if(recordlen == read(filefd, (void *)&temprecordheader, recordlen))
               {
                    memcpy(temprecordheader.data, historydata, datalen);
                    temprecordheader.datalen = datalen;
                    lseek(filefd, 256+writeindex*sizeof(HistoryRecordHeader), SEEK_SET);
                    if(write(filefd, &temprecordheader, sizeof(HistoryRecordHeader)) > 0)
                    {
                         return 0;
                    }
                    else
                    {
                        MY_ERROR_LOG("write error\n");
                        return -1;
                    }
               }
               else
               {
                 MY_ERROR_LOG("read error\n");
                 return -1;
               }
          }
          else
          {
            MY_ERROR_LOG("lseek error : %d\n", res);
            return -1;
          }
    }
    else
    {
         MY_ERROR_LOG("file no init\n");
         return -1;
    }     
     return 0;
}

int CHistoryRecord :: HistoryAdd(char *historydata, int datalen)
{
   if(0 == ISVALID_DATALEN(datalen) )
   {
       MY_ERROR_LOG("write data %d is more than max data len %d", datalen, HISTORY_RECORD_LEN);
       return - 1;
   }
   if(filefd >= 0 && fileheader->writeindex + 1 != fileheader->readindex)
   {
        
          int res = lseek(filefd, 256+fileheader->writeindex*sizeof(HistoryRecordHeader), SEEK_SET);
          if(res >= 0)
          {
            HistoryRecordHeader temprecordheader = {0};
            memcpy(temprecordheader.data, historydata, datalen);
            temprecordheader.datalen = datalen;
            temprecordheader.valid = 1;
            if(write(filefd, &temprecordheader, sizeof(HistoryRecordHeader)) > 0)
            {
                    fileheader->writeindex = (fileheader->writeindex + 1) % fileheader->maxrecord;
                    HistorySyncFileHeader();
                    return 0;
            }
            else
            {
                MY_ERROR_LOG("write error\n");
                return -1;
            }
          }
          else
          {
            MY_ERROR_LOG("lseek error : %d\n", res);
            return -1;
          }
   }
   else
   {
         MY_ERROR_LOG("file no init\n");
         return -1;
   }  
   return 0 ;   
}

int CHistoryRecord :: HistoryRead(char *readdata)
{
    if(filefd >= 0)
    {
     GET_VALID_DATA:        
          int res = lseek(filefd, 256+fileheader->readindex*sizeof(HistoryRecordHeader), SEEK_SET);
          if(res >= 0)
          {      
              HistoryRecordHeader temprecordheader = {0};
              int recordlen = sizeof(HistoryRecordHeader);
              if(recordlen == read(filefd, (void *)&temprecordheader, recordlen))
               {
                   if(1 == temprecordheader.valid)
                   {
                         memcpy(readdata, temprecordheader.data, temprecordheader.datalen);
                         fileheader->readindex = (fileheader->readindex + 1) % fileheader->maxrecord;
                         HistorySyncFileHeader();
                   }
                   else
                   {
                         fileheader->readindex = (fileheader->readindex + 1) % fileheader->maxrecord;
                         HistorySyncFileHeader();
                         goto GET_VALID_DATA;
                   }
               }
              else
               {
                 MY_ERROR_LOG("read error\n");
                 return -1;
               }
          }
          else
          {
            MY_ERROR_LOG("lseek error : %d\n", res);
            return -1;
          }
    }
    else
    {
         MY_ERROR_LOG("file no init\n");
         return -1;
    }     
     return 0;

}


int CHistoryRecord :: HistoryRead(char *readdata, int recordcount)
{


   return 0;
}


int CHistoryRecord :: HistoryRemainCount()
{
    if(NULL == fileheader)
     {
         return -1;
     }
     else
     {
         return ((fileheader->writeindex + fileheader->maxrecord) - fileheader->readindex)%fileheader->maxrecord;
     }
     return 0;
}


int CHistoryRecord :: HistorySyncFileHeader()
{

   if(filefd >= 0 || NULL == fileheader)
   {
     int res = lseek(filefd, 0, SEEK_SET);
     if(res >= 0)
      {
          if(write(filefd, (void *)fileheader, sizeof(HistoryFileHeader)) > 0)
            {
                
            }
            else
            {
                MY_ERROR_LOG("write error\n");
                return -1;
            }
      }
     else
      {
         MY_ERROR_LOG("lseek error : %d\n", res);
         return -1;
      }
   }
   else
   {
         MY_ERROR_LOG("file no init\n");
         return -1;
   }     
   return 0;
}